package com.tico.common.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * JSON的驼峰和下划线互转帮助类
 */
public class JsonUtils {


    public static <T> Object toUnderlineJSONString(Class<T> clazz, Object object, String[] array) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException, JsonProcessingException {
                arg1.writeString("");
            }
        });


        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        mapper.registerModule(simpleModule);

        JacksonJsonFilter jacksonFilter = new JacksonJsonFilter();
        jacksonFilter.include(clazz, array);
        mapper.setFilterProvider(jacksonFilter);
        mapper.addMixIn(clazz, jacksonFilter.getClass());
        String json = mapper.writeValueAsString(object);
        return convert(json);
    }


    public static <T> Object toUnderlineJSONFilterString(Class<T> clazz, Object object, String[] array) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException, JsonProcessingException {
                arg1.writeString("");
            }
        });

        SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm");
        mapper.setDateFormat(fmt);

        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        mapper.registerModule(simpleModule);

        JacksonJsonFilter jacksonFilter = new JacksonJsonFilter();
        jacksonFilter.filter(clazz, array);
        mapper.setFilterProvider(jacksonFilter);
        mapper.addMixIn(clazz, jacksonFilter.getClass());
        String json = mapper.writeValueAsString(object);
        return convert(json);
    }

    public static <T> Object toUnderlineJSONFilterString(Class<T> clazz, Object object, String pattern, String[] array) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.getSerializerProvider().setNullValueSerializer(new JsonSerializer<Object>() {
            @Override
            public void serialize(Object arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException, JsonProcessingException {
                arg1.writeString("");
            }
        });

        SimpleDateFormat fmt = new SimpleDateFormat(pattern);
        mapper.setDateFormat(fmt);

        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        mapper.registerModule(simpleModule);

        JacksonJsonFilter jacksonFilter = new JacksonJsonFilter();
        jacksonFilter.filter(clazz, array);
        mapper.setFilterProvider(jacksonFilter);
        mapper.addMixIn(clazz, jacksonFilter.getClass());
        String json = mapper.writeValueAsString(object);
        return convert(json);
    }


    private static void convert(Object json) {
        if (json instanceof JSONArray) {
            JSONArray arr = (JSONArray) json;
            for (Object obj : arr) {
                convert(obj);
            }
        } else if (json instanceof JSONObject) {
            JSONObject jo = (JSONObject) json;
            Set<String> keys = jo.keySet();
            String[] array = keys.toArray(new String[keys.size()]);
            for (String key : array) {
                Object value = jo.get(key);
                jo.remove(key);
                jo.put(camelToUnderline(key), value);
                convert(value);
            }
        }
    }


    private static Object convert(String json) {
        Object obj = JSON.parse(json);
        convert(obj);
        return obj;
    }


    private static final char UNDERLINE = '_';

    private static String camelToUnderline(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(UNDERLINE);
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static String keyValue(String k,String str){
        String value ="";
        List<Object> os = new ArrayList<>();
        Map<String, Object> stringObjectMap = JsonUtils.parseJSON2Map(str);
        for (String s:stringObjectMap.keySet()){
            if(s.equals(k)){
                value = (String)stringObjectMap.get(s);
                return value;
            }
            String simpleName = stringObjectMap.get(s).getClass().getSimpleName();
            if(simpleName.equals("JSONObject")){
                Object o = stringObjectMap.get(s);
                os.add(o);
            }
        }
        for(Object o :os){
            String s = keyValue(k, JSONObject.toJSONString(o));
            if(!StringUtils.isEmpty(s)){
                return s;
            }
        }
        return value;
    }

    public static Map<String, Object> parseJSON2Map(String jsonStr) {
        Map<String, Object> map = new HashMap<String, Object>();
// 最外层解析
        JSONObject json = JSONObject.parseObject(jsonStr);
        for (Object key : json.keySet()) {
            Object value = json.get(key);
            // 判断内层对象类型，如果还是数组的话，继续解析
            if (value instanceof JSONArray) {
                List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
                Iterator<Object> it = ((JSONArray) value).iterator();
                while (it.hasNext()) {
                    Object json2 = it.next();
                    list.add(parseJSON2Map(json2.toString()));
                }
                map.put(key.toString(), list);
            } else {
                map.put(key.toString(),value);
            }
        }
        return map;
    }
    public static Map JsonToMap(Stack<JSONObject> stObj, Map<String, Object> resultMap) throws Exception {
        if (stObj == null && stObj.pop() == null) {
            return null;
        }
        JSONObject json = stObj.pop();
        Set<String> strings = json.keySet();
        Iterator it = strings.iterator();
        while (it.hasNext()) {
            String key = (String) it.next();
            //得到value的值
            Object value = json.get(key);

            if (value instanceof JSONObject) {
                stObj.push((JSONObject) value);
                //递归遍历
                JsonToMap(stObj, resultMap);
            } else {
                resultMap.put(key, value);
            }

        }
        return resultMap;
    }
}